package com.dongbao.checkin;

import com.alibaba.fastjson.JSON;
import com.dongbao.data.Datacenter;
import com.dongbao.entity.AuditFileInfo;
import com.dongbao.entity.FileLog;
import com.dongbao.entity.MqMessage;
import com.dongbao.service.CodeGradeBiz;
import com.dongbao.service.MyMqttClient;
import com.dongbao.util.InitUtil;
import com.intellij.ide.todo.*;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.CommitExecutor;
import com.intellij.openapi.vcs.changes.ui.BooleanCommitOption;
import com.intellij.openapi.vcs.checkin.CheckinHandler;
import com.intellij.openapi.vcs.ui.CommitMessage;
import com.intellij.openapi.vcs.ui.Refreshable;
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.labels.LinkListener;
import com.intellij.util.Consumer;
import com.intellij.util.PairConsumer;
import com.intellij.vcs.commit.message.CommitMessageInspectionsPanel;
import com.intellij.vcs.log.impl.VcsCommitMetadataImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.dongbao.common.MessageConstant.CORE_CLASS_AUDIT_MESSAGE;
import static com.intellij.CommonBundle.getCancelButtonText;
import static com.intellij.openapi.ui.Messages.*;
import static com.intellij.util.ui.UIUtil.getWarningIcon;

public class DHGCheckinHandler extends CheckinHandler {

    private static final String COMMIT_DHG_CODE_CHECK = "COMMIT_DHG_CODE_CHECK";

    private final Project myProject;
    private final CheckinProjectPanel myCheckinProjectPanel;
    private final VcsConfiguration myConfiguration;
    private TodoFilter myTodoFilter;

    public DHGCheckinHandler(CheckinProjectPanel checkinProjectPanel) {
        myProject = checkinProjectPanel.getProject();
        myCheckinProjectPanel = checkinProjectPanel;
        myConfiguration = VcsConfiguration.getInstance(myProject);
    }

    @Override
    public RefreshableOnComponent getBeforeCheckinConfigurationPanel() {

        final JCheckBox checkBox = new JCheckBox("DHG提交规范检查");

        return new BooleanCommitOption(myCheckinProjectPanel, "DHG代码提交检查", true,
                () -> myConfiguration.CHECK_NEW_TODO, value -> myConfiguration.CHECK_NEW_TODO = value) {
            @NotNull
            @Override
            public JComponent getComponent() {
                JPanel panel = new JPanel(new BorderLayout(4, 0));
                panel.add(checkBox, BorderLayout.WEST);

                checkBox.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        PropertiesComponent.getInstance().setValue(COMMIT_DHG_CODE_CHECK, checkBox.isSelected());
                        System.out.println("checkBox_actionPerformed:" + checkBox.isSelected());
                    }
                });

                setFilterText(myConfiguration.myTodoPanelSettings.todoFilterName);
                if (myConfiguration.myTodoPanelSettings.todoFilterName != null) {
                    myTodoFilter = TodoConfiguration.getInstance().getTodoFilter(myConfiguration.myTodoPanelSettings.todoFilterName);
                }

                Consumer<TodoFilter> consumer = todoFilter -> {
                    myTodoFilter = todoFilter;
                    String name = todoFilter == null ? null : todoFilter.getName();
                    myConfiguration.myTodoPanelSettings.todoFilterName = name;
                    setFilterText(name);
                };
                LinkLabel linkLabel = new LinkLabel(VcsBundle.message("settings.filter.configure.link"), null);
                linkLabel.setListener(new LinkListener() {
                    @Override
                    public void linkSelected(LinkLabel aSource, Object aLinkData) {
                        DefaultActionGroup group = SetTodoFilterAction.createPopupActionGroup(myProject, myConfiguration.myTodoPanelSettings, consumer);
                        ActionPopupMenu popupMenu = ActionManager.getInstance().createActionPopupMenu(ActionPlaces.TODO_VIEW_TOOLBAR, group);
                        popupMenu.getComponent().show(linkLabel, 0, linkLabel.getHeight());
                    }
                }, null);
                panel.add(linkLabel, BorderLayout.CENTER);
                return panel;
            }

            @Override
            public void saveState() {
                PropertiesComponent.getInstance().setValue(COMMIT_DHG_CODE_CHECK, checkBox.isSelected());
            }

            @Override
            public void restoreState() {
                checkBox.setSelected(isCheckMessageEnabled());
            }

            private void setFilterText(String filterName) {
                if (filterName == null) {
                    getCheckBox().setText("DHG代码提交检查");
                }
                else {
                    getCheckBox().setText("DHG代码提交检查_Filter:"+filterName);
                }
            }
        };
    }

    public static boolean isCheckMessageEnabled() {
        return PropertiesComponent.getInstance().getBoolean(COMMIT_DHG_CODE_CHECK, true);
    }



    @Override
    public ReturnResult beforeCheckin(@Nullable CommitExecutor executor, PairConsumer<Object, Object> additionalDataConsumer) {
        boolean isCheck = PropertiesComponent.getInstance().getBoolean(COMMIT_DHG_CODE_CHECK);
        if(!isCheck){
            return ReturnResult.COMMIT;
        }
        /* 检测MQ是否链接成功 */
        if(Datacenter.protectFiles.size()==0){
            InitUtil.initFileList();
        }
        /* 如果IDEA在给项目创建索引的时候提交检查,则进行提示不允许在项目创建索引时提交内容 */
        if (DumbService.getInstance(myProject).isDumb()) {
            String todoName = "DHG代码提交检查_title";
            if (showOkCancelDialog(myProject,
                    todoName +
                            " can't be performed while " + ApplicationNamesInfo.getInstance().getFullProductName() + " updates the indices in background.\n" +
                            "You can commit the changes without running checks, or you can wait until indices are built.",
                    todoName + " is not possible right now",
                    "&Wait", "&Commit", null) == OK) {
                return ReturnResult.CANCEL;
            }
            return ReturnResult.COMMIT;
        }
        /* 获取当前提交的文件集合 */
        Collection<Change> changes = myCheckinProjectPanel.getSelectedChanges();
        CodeGradeBiz codeGradeBiz = new CodeGradeBiz();
        DHGCheckinHandlerWorker worker = new DHGCheckinHandlerWorker(myProject, changes, myTodoFilter,codeGradeBiz);
        worker.execute();

//        CommitMessageI commitPanel = getCommitPanel(actionEvent);
        /* 修改提交的内容注释,增加分数的注释 */
//        myCheckinProjectPanel.setCommitMessage("本次代码评分:"+worker.allScoreInfo.getScore()+"\n提交内容:"+myCheckinProjectPanel.getCommitMessage());
        return showResults(worker, executor);
    }



    @Nullable
    private static CommitMessageI getCommitPanel(@Nullable AnActionEvent e) {
        if (e == null) {
            return null;
        }
        Refreshable data = Refreshable.PANEL_KEY.getData(e.getDataContext());
        if (data instanceof CommitMessageI) {
            return (CommitMessageI) data;
        }
        return VcsDataKeys.COMMIT_MESSAGE_CONTROL.getData(e.getDataContext());
    }

    private ReturnResult showResults(DHGCheckinHandlerWorker worker, CommitExecutor executor) {
        String commitButtonText = executor != null ? executor.getActionText() : myCheckinProjectPanel.getCommitActionName();
        commitButtonText = StringUtil.trimEnd(commitButtonText, "...");

        String text = "您当前提交的文件中存在模块核心业务代码,请向该模块负责人申请审核通过后提交！";
        boolean thereAreTodoFound = worker.getCoreFiles().size() > 0;
        String title = "DHG核心业务代码提交";
        if (thereAreTodoFound) {
            /* 检测到存在核心业务类 则弹窗提示审核信息 */
            return askReviewOrCommit(worker, "强制提交", text, title);
        }
//        else if (YES == showYesNoDialog(myProject, text, title, commitButtonText, getCancelButtonText(), getWarningIcon())) {
//            /* 是否强制提交 */
//            return ReturnResult.COMMIT;
//        }
        /* 没有任何检测到存在就提交 */
        return ReturnResult.COMMIT;
    }

    /**
     * 根据弹窗来确定是否强制提交 还是 关闭取消勾选选择的不合规则的文件
     * */
    @NotNull
    private ReturnResult askReviewOrCommit(@NotNull DHGCheckinHandlerWorker worker,
                                           @NotNull String commitButton,
                                           @NotNull String text,
                                           @NotNull String title) {
        String yesButton = "提交审核";
        switch (showYesNoCancelDialog(myProject, text, title, yesButton, commitButton, getCancelButtonText(), getWarningIcon())) {
            case YES:
                /* 使用mqtt发送审核信息给 对应ip的负责人审核diamante */
                sendAuditInfoToLeader(worker);
                return ReturnResult.CLOSE_WINDOW;
            case NO:
                /* 关闭 什么都不干 */
                return ReturnResult.COMMIT;
        }
        return ReturnResult.CANCEL;
    }

    private void sendAuditInfoToLeader(@NotNull DHGCheckinHandlerWorker worker){
        /* 遍历发送拦截到的核心类 */
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {

                Set<VirtualFile> coreFiles = worker.getCoreFiles();
                for(VirtualFile  coreFile:coreFiles){
                    List<FileLog> fileLogs = Datacenter.protectFiles.stream().filter(log -> log.getFileName().equals(coreFile.getName())).collect(Collectors.toList());
                    FileLog fileLog = fileLogs.get(0);
                    String leaderIps = fileLog.getLeaderIp();
                    List<String> ipArrays = Arrays.asList(leaderIps.split(","));
                    /* 去除为null的数组元素 */
                    ipArrays = ipArrays.stream().filter(item->{return item!=null;}).collect(Collectors.toList());
                    for(String leaderIp:ipArrays){
                        /* 发送消息 */
                        MqMessage message = MqMessage.getInstance();
                        message.setCode(CORE_CLASS_AUDIT_MESSAGE);
                        message.setMessage(String.format("您的【%s】正在被人修改,修改者ip为【%s】",fileLog.getFileName(),Datacenter.clientIp));

                        AuditFileInfo auditFileInfo=new AuditFileInfo();
                        auditFileInfo.setContent(new String(coreFile.contentsToByteArray()));
                        auditFileInfo.setFilePath(coreFile.getPath());
                        auditFileInfo.setFileName(coreFile.getName());

                        message.setData(JSON.toJSON(auditFileInfo));
                        message.setRows(Arrays.asList(coreFile.getName()));
                        Datacenter.myMqttClient.publishMessage(MyMqttClient.TOPIC_PREFIX+leaderIp,message,0);
                    }
                }
                return 3;
            }
        });
    }

}
